package com.autohammal.monitor.scheduler.implement;

import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import com.autohammal.monitor.scheduler.Scheduler;
import com.autohammal.monitor.scheduler.support.SchedulerUnit;

/**
 * Use ScheduledExecutorService to instead of Timer
 * 
 * @author dailey_dai Nov 11, 2011
 * 
 */
public class AdvanceScheduler implements Scheduler {
	private static final long serialVersionUID = -8167017079790866574L;
	private ScheduledExecutorService executorService = null;
	private SchedulerUnit scheduleUnit = null;
	private Lock lock = new ReentrantLock();

	public AdvanceScheduler(SchedulerUnit scheduleUnit) {
		setScheduleUnit(scheduleUnit);
		initialExecutorService();
	}

	public AdvanceScheduler() {
		initialExecutorService();
	}

	protected void initialExecutorService() {
		lock.lock();
		try {
			executorService=new ScheduledThreadPoolExecutor(10,new RejectedExecutionHandler() {
				@Override
				public void rejectedExecution(Runnable r,
						ThreadPoolExecutor executor) {
					Logger.getLogger(AdvanceScheduler.class).log(Level.ERROR,
							r.toString() + " give it up.");
				}
			});
		} finally {
			lock.unlock();
		}
	}

	public SchedulerUnit getScheduleUnit() {
		return scheduleUnit;
	}

	public void setScheduleUnit(SchedulerUnit scheduleUnit) {
		this.scheduleUnit = scheduleUnit;
	}

	@Override
	public void schedule(Runnable runnable) {
		if (executorService == null || executorService.isShutdown()) {
			initialExecutorService();
		}
		if (scheduleUnit == null)
			throw new NullPointerException("SchedulerUnit can not be null.");
		switch (scheduleUnit.getFixedType()) {
		case DELAY:
			executorService.scheduleWithFixedDelay(runnable,
					scheduleUnit.getFirst(), scheduleUnit.getDelay(),
					scheduleUnit.getTimeUnit());
			break;
		default:
			executorService.scheduleAtFixedRate(runnable,
					scheduleUnit.getFirst(), scheduleUnit.getPeriod(),
					scheduleUnit.getTimeUnit());
		}
	}

	@Override
	public synchronized void cancel() {
		lock.lock();
		try {
			if (executorService != null && !executorService.isShutdown()) {
				executorService.shutdownNow();
				Logger.getLogger(WorkDaysScheduler.class).log(Level.DEBUG,
						"Scheduler is shutdown");
			}
		} finally {
			lock.unlock();
		}
	}

}
